package graph.net.commands;

import graph.net.internal.HelpReference;
import graph.net.internal.ServiceLocator;
import graph.service.NoSuchRouteException;

/*************************************************************
 * @author amahmood
 *Process all commands related to graph service.
 ************************************************************/
public class GraphCommand extends AbstractGraphCommand
{

    /*************************************************************
     * @param serviceLocator
     ************************************************************/
    public GraphCommand(ServiceLocator serviceLocator)
    {
       super(serviceLocator);
    }

    /* ***********************************************************
     * @see mule.ps1.net.commands.ICommand#execute(java.lang.String[])
     ************************************************************/
    public String execute(String[] parameters) throws InvalidCommandFormatException
    {
        CommandName commandName = CommandName.valueOf(parameters[0]);

        String response = "";

        switch (commandName)
        {
            case add_route:
                response = executeAddRoute(parameters);
                break;

            case find_all_paths_less_then_distance:
                response = executePathsLessThenDistance(parameters);
                break;

            case find_paths_with_max_stops:
                response = executePathsWithMaxStop(parameters);
                break;
                
            case find_paths_with_exact_stops:
                response = executePathsWithExactStop(parameters);
                break;
                
            case find_shortest_path_length:
                response = executeShortestPath(parameters);
                break;

            case find_distance:
                response = executeFindDistance(parameters);
                break;
                
            default:
                return "Command is not implemented yet.";
        }

        return response;
    }


    /*************************************************************
     * @param parameters
     * @return
     * @throws InvalidCommandFormatException 
     ************************************************************/
    private String executeAddRoute(String[] parameters) throws InvalidCommandFormatException
    {
        validateRout(parameters);

        char from = parameters[1].charAt(0);
        char to = parameters[1].charAt(1);
        int distance = Integer.parseInt(parameters[1].charAt(2)+"");

        serviceLocator.getGraphService().addEdge(from, to, distance);

        return "Route added";
    }

    /*************************************************************
     * @param parameters
     * @return
     * @throws InvalidCommandFormatException 
     ************************************************************/
    private String executePathsLessThenDistance(String[] parameters) throws InvalidCommandFormatException
    {
        validatePreConditionsFromToInt(parameters);
        
        String from = parameters[1];
        String to = parameters[2];
        int distance = Integer.parseInt(parameters[3]);

        int result = serviceLocator.getGraphService().allPathsLessThanDistance(from.charAt(0), to.charAt(0),
                distance);

        return Integer.toString(result);
    }

    /*************************************************************
     * @param parameters
     * @return
     * @throws InvalidCommandFormatException 
     ************************************************************/
    private String executePathsWithMaxStop(String[] parameters) throws InvalidCommandFormatException
    {
        validatePreConditionsFromToInt(parameters);

        String from = parameters[1];
        String to = parameters[2];
        int stops = Integer.parseInt(parameters[3]);

        int result = serviceLocator.getGraphService().countPathsWithMaxStop(from.charAt(0), to.charAt(0), stops);

        return Integer.toString(result);
    }

    

    /*************************************************************
     * @param parameters
     * @return
     * @throws InvalidCommandFormatException 
     ************************************************************/
    private String executePathsWithExactStop(String[] parameters) throws InvalidCommandFormatException
    {
        validatePreConditionsFromToInt(parameters);

        String from = parameters[1];
        String to = parameters[2];
        int stops = Integer.parseInt(parameters[3]);

        int result = serviceLocator.getGraphService().countPathsWithExactStop(from.charAt(0), to.charAt(0), stops);

        return Integer.toString(result);
    }    
    /*************************************************************
     * @param parameters
     * @return
     * @throws InvalidCommandFormatException 
     ************************************************************/
    private String executeShortestPath(String[] parameters) throws InvalidCommandFormatException
    {
        validatePreConditionsFromTo(parameters);

        String from = parameters[1];
        String to = parameters[2];

        long result = serviceLocator.getGraphService().shortestDistance(from.charAt(0), to.charAt(0));

        return Long.toString(result);
    }

    /***************************************************************
     * @param parameters
     * @return
     **************************************************************/
    private String executeFindDistance(String[] parameters)
    {
        Long result=0l;
        try
        {
            result = serviceLocator.getGraphService().caculateDistance(parameters[1]);
        }
        catch (NoSuchRouteException e)
        {
            return e.getMessage();
        }

        return Long.toString(result);
    }

    /*************************************************************
     * @param parameters
     ************************************************************/
    private void validatePreConditionsFromTo(String[] parameters) throws InvalidCommandFormatException
    {

        if (parameters == null )
        { 
            throw new IllegalArgumentException(
                "One of the required parameter is null.");
        }

        if (parameters.length != 3)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

        if (parameters[1].length() != 1)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

        if (parameters[2].length() != 1)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

    }

    /*************************************************************
     * @param parameters
     ************************************************************/
    private void validatePreConditionsFromToInt(String[] parameters) throws InvalidCommandFormatException
    {
        if (parameters == null )
        { 
            throw new IllegalArgumentException(
                "One of the required parameter is null.");
        }

        if (parameters.length != 4)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

        if (parameters[1].length() != 1)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

        if (parameters[2].length() != 1)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }

        if (!isValidNumber(parameters[3]))
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException("Invalid command format " + message);
        }
    }
    
    
    /**************************************************************
     * @param parameters
     * @throws InvalidCommandFormatException
     *************************************************************/
    private void validateRout(String[] parameters) throws InvalidCommandFormatException
    {
        if (parameters ==null)
        {
            throw new IllegalArgumentException(
            "One of the required parameter is null.");
        }
        
        if (parameters.length !=2)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException(
            "InvalidCommandForamt "+ message);
        }
        
        if (parameters[1].length() !=3)
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException(
            "InvalidCommandForamt "+ message);
        }
        
        if (!isValidNumber(parameters[1].charAt(2)))
        {
            String message = HelpReference.getInstance().getHelp(parameters[0]);
            throw new InvalidCommandFormatException(
            "InvalidCommandForamt "+ message);            
            
        }
            
            
    }
    
    /**************************************************************
     * @param number
     * @return
     *************************************************************/
    private boolean isValidNumber(String number)
    {
        try
        {
            Integer.parseInt(number);
            return true;
        }
        catch (Exception e)
        {
            System.err.println(e.getMessage());
        }
        
        return false;
    }

    
    /**************************************************************
     * @param number
     * @return
     *************************************************************/
    private boolean isValidNumber(char number)
    {
       return isValidNumber(number+"");
    } 
}
